<?php

namespace service\impl;

use service\exception\ServiceException;
use service\ext\PageData;
use service\service\PracticeSubjectService;
use service\vo\practice\PracticeSubject;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

class PracticeSubjectServiceImpl extends BaseImpl implements PracticeSubjectService
{

    //当前模块名称
    private static string $modeName = 'practiceSubject';

    /**
     * @inheritDoc
     */
    public function addPracticeSubject(PracticeSubject $practiceSubject): int
    {
        // TODO: Implement addPracticeSubject() method.
        $data = [
            self::$FIELD_COMMON_U_ID => $practiceSubject->getUserId(),
            self::$FIELD_PRACTICE_SUBJECT_PRACTICE_ID => $practiceSubject->getPracticeId(),
            self::$FIELD_COMMON_SUBJECT_ID => $practiceSubject->getSubjectId(),
            self::$FIELD_PRACTICE_SUBJECT_TRANSLATION => $practiceSubject->getTranslation(),
            self::$FIELD_PRACTICE_SUBJECT_ADD_TIME => date('Y-m-d H:i:s'),
        ];
        return $this->getPracticeSubjectDb($practiceSubject->getUserId())->insertGetId($data);
    }


    /**
     * @throws DbException
     */
    public function updatePracticeSubjectTranslation(int $userId, int $id, string $translation): int
    {
        // TODO: Implement updatePracticeSubjectTranslation() method.
        return $this->getPracticeSubjectDb($userId)
            ->where(self::$FIELD_COMMON_ID, $id)
            ->update([
                self::$FIELD_PRACTICE_SUBJECT_TRANSLATION => $translation
            ]);
    }

    /**
     * @throws DbException
     */
    public function deletePracticeSubjectById(int $userId, int $id): int
    {
        // TODO: Implement deletePracticeSubjectById() method.
        return $this->getPracticeSubjectDb($userId)
            ->where(self::$FIELD_COMMON_ID, $id)
            ->delete();
    }

    /**
     * @throws DbException
     */
    public function deletePracticeSubjectByIds(int $userId, array $ids): int
    {
        // TODO: Implement deletePracticeSubjectByIds() method.
        return $this->getPracticeSubjectDb($userId)
            ->whereIn(self::$FIELD_COMMON_ID, $ids)
            ->delete();
    }

    /**
     * @throws DbException
     */
    public function deletePracticeSubjectByUserId(int $userId): int
    {
        // TODO: Implement deletePracticeSubjectByUserId() method.
        return $this->getPracticeSubjectDb($userId)
            ->where(self::$FIELD_COMMON_U_ID, $userId)
            ->delete();
    }

    /**
     * @throws ServiceException
     */
    public function getPracticeSubjectById(int $userId, int $id): PracticeSubject
    {
        // TODO: Implement getPracticeSubjectById() method.
        $po = $this->getPracticeSubjectDb($userId)
            ->where(self::$FIELD_COMMON_ID, $id)
            ->findOrEmpty();
        if(empty($po)){
            throw new ServiceException(self::$modeName, self::ERROR_PRACTICE_SUBJECT_NOT_EXISTS);
        }
        return $this->getPracticeSubjectVoFromPo($po);
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getPracticeSubjectByIds(int $userId, array $ids): array
    {
        // TODO: Implement getPracticeSubjectByIds() method.
        $voArr = [];
        $poArr = $this->getPracticeSubjectDb($userId)
            ->whereIn(self::$FIELD_COMMON_ID, $ids)
            ->select();
        foreach ($poArr as $po){
            $voArr[] = $this->getPracticeSubjectVoFromPo($po);
        }
        return $voArr;
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getPracticeSubjectsByUserId(int $userId): array
    {
        // TODO: Implement getPracticeSubjectsByUserId() method.
        $voArr = [];
        $poArr = $this->getPracticeSubjectDb($userId)
            ->where(self::$FIELD_COMMON_U_ID, $userId)
            ->select();
        foreach ($poArr as $po){
            $voArr[] = $this->getPracticeSubjectVoFromPo($po);
        }
        return $voArr;
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getPracticeSubjectsByPracticeId(int $userId, int $practiceId): array
    {
        // TODO: Implement getPracticeSubjectsByPracticeId() method.
        $voArr = [];
        $poArr = $this->getPracticeSubjectDb($userId)
            ->whereIn(self::$FIELD_PRACTICE_SUBJECT_PRACTICE_ID, $practiceId)
            ->select();
        foreach ($poArr as $po){
            $voArr[] = $this->getPracticeSubjectVoFromPo($po);
        }
        return $voArr;    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function getPracticeSubjectsByPracticeIds(int $userId, array $practiceIds): array
    {
        // TODO: Implement getPracticeSubjectsByPracticeIds() method.
        $voArr = [];
        $poArr = $this->getPracticeSubjectDb($userId)
            ->whereIn(self::$FIELD_PRACTICE_SUBJECT_PRACTICE_ID, $practiceIds)
            ->select();
        foreach ($poArr as $po){
            $voArr[] = $this->getPracticeSubjectVoFromPo($po);
        }
        return $voArr;
    }

    /**
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws ServiceException
     */
    public function searchPracticeSubjects(int $currentPage, int $pageSize, array $filterCriteria, array $sorterCriteria): PageData
    {
        // TODO: Implement searchPracticeSubjects() method.
        if(empty($filterCriteria[self::$FILTER_USER_ID])){
            throw new ServiceException(self::$modeName, self::ERROR_PRACTICE_SUBJECT_USER_ID);
        }
        $userId = $filterCriteria[self::$FILTER_USER_ID];
        $filter = [];
        if (!empty($filterCriteria)) {
            foreach ($filterCriteria as $key => $value) {
                if (strcasecmp($key, self::$FILTER_USER_ID) == 0) {
                    //用户id
                    $filter[] = [self::$FIELD_COMMON_U_ID, "=", $value];
                } elseif (strcasecmp($key, self::$FILTER_ADD_TIME) == 0) {
                    //时间
                    $betweenTime = makeBetween($value['start'], $value['end']);
                    $filter[] = [self::$FIELD_PRACTICE_SUBJECT_ADD_TIME, $betweenTime[0], $betweenTime[1]];
                } elseif (strcasecmp($key, self::$FILTER_PRACTICE_ID) == 0) {
                    //练习配置id
                    $filter[] = [self::$FIELD_PRACTICE_SUBJECT_PRACTICE_ID, "=", $value];
                } elseif (strcasecmp($key, self::$FILTER_SUBJECT_ID) == 0) {
                    //习题id
                    $filter[] = [self::$FIELD_COMMON_SUBJECT_ID, "=", $value];
                }
            }
        }

        //构建排序条件
        $sort = [];
        if (!empty($sorterCriteria)) {
            foreach ($sorterCriteria as $key => $value) {
                if (strcasecmp($key, self::$SORT_ID) == 0) {
                    $sort[self::$FIELD_COMMON_ID] = $value ? self::$SORT_VALUE_ASC : self::$SORT_VALUE_DESC;
                }
            }
        }
        $count = $this->getPracticeSubjectDb($userId)
            ->where($filter)
            ->count();

        $list = $this->getPracticeSubjectDb($userId)
            ->where($filter)
            ->order($sort)
            ->limit($pageSize)
            ->page($currentPage)
            ->select();

        $dataList = [];
        foreach ($list as $po) {
            $dataList[] = $this->getPracticeSubjectVoFromPo($po);
        }

        $pageData = new PageData();
        $pageData->setData($dataList);
        $pageData->setCount($count);

        return $pageData;
    }

    private function getPracticeSubjectVoFromPo($po): PracticeSubject
    {
        $vo = new PracticeSubject();
        $vo->setId($po[self::$FIELD_COMMON_ID]);
        $vo->setUserId($po[self::$FILTER_USER_ID]);
        $vo->setAddTime(self::$FIELD_PRACTICE_SUBJECT_ADD_TIME);
        $vo->setPracticeId($po[self::$FIELD_COMMON_ID]);
        $vo->setSubjectId($po[self::$FIELD_COMMON_SUBJECT_ID]);
        $vo->setTranslation($po[self::$FIELD_PRACTICE_SUBJECT_TRANSLATION]);
        return $vo;
    }
}